﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Grishko.DataTier;
using OutdoorLib.Context;
using OutdoorLib.BaseEntity.WS;
using OutdoorLib.BaseEntity.Agency;
using Grishko.SerilizeTools;
using System.ComponentModel;

namespace OutdoorLib.BaseEntity.Dictionary
{
    /// <summary>
    /// Базовый класс справочников имеющих иерархическую структуру 
    /// Адресная программа,справочник типов рекламны поверхностей и т.д.
    /// </summary>
    public class TreeDictionaryItem : DictionaryItem
    {
        
        /// <summary>
        /// ветка справочника
        /// </summary>
        public class BranchItem : DictionaryItem
        {
            public override string ParamID
            {
                get
                {
                    return ID;
                }
                set
                {
                    ID = value;
                }
            }
        }

        #region Категории древовидных справочников

        /// <summary>
        /// Справочник типов конструкций 
        /// </summary>
        public const string TreeDictionary_ConstractionType = "3E5A3086-2A46-4051-9CE8-934976E40AC8";
        /// <summary>
        /// справочник адресная программа
        /// </summary>
        public const string TreeDictionary_AdressProgram = "991F97B3-6314-413D-9FD1-24157CF0479D";

        /// <summary>
        /// справочник улицы
        /// </summary>
        public const string TreeDictionary_Streets = "EFB070F5-D940-4228-BE7B-08036D0E1BEC";

        /// <summary>
        /// справочник ограничения носителя
        /// </summary>
        public const string TreeDictionary_ConstractionConditions = "ED90F24F-2177-4121-9600-FD0F4A978C55";

        /// <summary>
        /// справочник - географическая привязка привяка
        /// </summary>
        public const string TreeDictionary_GeoBinding = "BADB2B14-9D6C-4C69-9EDD-8D5831009852";

        /// <summary>
        /// справочник транспортное положение конструкции
        /// </summary>
        public const string TreeDictionary_LocationDescribe = "45A6FF02-E731-4D4F-906E-DE2943E82A1D";

        /// <summary>
        /// Ограничения на размещение
        /// </summary>
        public const string TreeDictionary_RestrictionsOnPlacement = "185956C0-A0D6-409A-ABBE-37D0986329C4";

        

        /// <summary>
        ///  Категория клиента (дерево - специализации)
        /// </summary>
        public const string TreeDictionary_ClientsCategory = "CF128840-C898-41D1-8F68-042287F9B054";


        /// <summary>
        /// Статус клиента (потенциальный клиент и т.п.)
        /// </summary>
        public const string TreeDictionary_ClientStatus = "1BEAA476-1462-48C0-8000-72AEE2F99592";


        /// <summary>
        /// Категории задач
        /// </summary>
        public const string TreeDictionary_TaskCategory = "B5F499C5-B48B-4B0B-AB2B-73320C746B53";

        #endregion

        /// <summary>
        /// сформировать вершину для набора справочников (тип справочника, имя вершины)
        /// </summary>
        /// <returns></returns>
        public static TreeDictionaryItem GetProxyRoot(string TypeID, string sName)
        {
            TreeDictionaryItem tree = new TreeDictionaryItem() { TypeID = TreeDictionaryItem.TreeDictionary_AdressProgram, ParamID = qProxyId, ID = qProxyId, Value = sName };
            return tree ;
        }

        public class DictionaryItemComparer : IEqualityComparer<DictionaryItem>
        {

            public DictionaryItemComparer()
            {

            }
            #region IEqualityComparer<DictionaryItem> Members

            public bool Equals(DictionaryItem x, DictionaryItem y)
            {
                return (x.ParamID == y.ParamID && y.Value == x.Value);
            }

            public int GetHashCode(DictionaryItem obj)
            {
                return obj.GetHashCode();
            }

            #endregion
        }

        /// <summary>
        /// Глубина справочника 
        /// </summary>
        [DefaultValue(2)]
        public string DeepLevel { get;set; }

        /// <summary>
        /// Ид типа справочника 
        /// </summary>
        public string TypeID { get{return ParamID ;  }set { ParamID = value; }}

        /// <summary>
        /// Name 
        /// </summary>
        public virtual string Name 
        { 
            get {return Value.ToString (); }
           set {Value =value ;}
        }

        [EntityNonSerialized]
        public override string ParamID
        {
            get
            {
                return base.ParamID;
            }
            set
            {
                base.ParamID = value;
            }
        }

        [EntityNonSerialized]
        public override object Value
        {
            get
            {
                return base.Value;
            }
            set
            {
                base.Value = value;
            }
        }

        /// <summary>
        /// сформировать TreeDictionaryItemValue  соответсвующую справочнику
        /// </summary>
        /// <returns></returns>
        public TreeDictionaryItemValue BuildValue()
        {
            TreeDictionaryItemValue r = new TreeDictionaryItemValue() 
            {   Name = this.Name, 
                TreeDictionaryTypeID = this.TypeID, 
                ID = this.ID };
            return r;
        }

        /// <summary>
        /// Построить хранилище значений справочника от текущего элемента
        /// Строит цепочку параметр значение от текущего эемента к корню
        /// </summary>
        /// <param name="Dictionatry"></param>
        /// <param name="NodeId">Id ноды от которой будут строиться справочники </param>
        /// <returns></returns>
        public TreeDictionaryItemValue BuildValue(string NodeId)
        {
            // Находим листок
            DictionaryItem Leaf = (DictionaryItem)this.Find(NodeId);
            if (null == Leaf) return null;

            // создаем структуру справочника 
            TreeDictionaryItemValue r = BuildValue();


            Func<DictionaryItem, EntityList, EntityList> fBuilder = delegate(DictionaryItem Source, EntityList NdVal)
            {
                if (Source.ParentNode != null)
                {
                    if ((Source.ParentNode as DictionaryItem).ParamID.IndexOf(AgencyLib_GlobalConstants.qProxyId) == -1)
                    {
                        NdVal.Add(new DictionaryItem() { Value = Source.ID, ParamID = Source.ParentNode.ID });
                    }
                    else /// Если это прокси делаем из соурса вершину справочника 
                    {
                        r.ID = Source.ID;

                        //Source.ParentNode.ID = Source.ID;
                    }
                }

                return NdVal;
            };


            Func<DictionaryItem, bool> CallBack = delegate(DictionaryItem Source)
            {
                r.ID = Source.ID;
                return true;
            };

            FindNext(Leaf, r.ChildNodes, fBuilder, CallBack);

            if (0 == r.ChildNodes.Count) return null;  // Значений нет ?                        

            return r;
        }

        /// <summary>
        /// Вернуть TreeDictionaryItemValue как текст
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public string GetValueAsString(TreeDictionaryItemValue value)
        {
            DictionaryItem root = (DictionaryItem)this.First;
            StringBuilder sBuilder = new StringBuilder();

            TreeDictionaryItemValue.Comparer cmp = new TreeDictionaryItemValue.Comparer();
            HashSet<DictionaryItem> Values = value.ChildNodes.ToHashSet<DictionaryItem>(cmp);

            string _RootNodeId = string.Empty;
            Func<DictionaryItem, StringBuilder> fBuild = delegate(DictionaryItem nd)
            {
                if (null == nd)
                    return sBuilder;

                // Корень спрваочника не выводим
                if (nd.ParentNode == null)
                {
                    _RootNodeId = nd.ID;
                    return sBuilder;
                }

                if (nd.ParentNode.ID == AgencyLib_GlobalConstants.qProxyId)
                {
                    _RootNodeId = nd.ID;
                    return sBuilder;
                }
                ///////////////////////////////////////////////////////////////////////

                string term = (_RootNodeId == nd.ParentNode.ID ? "|" : " ");
                DictionaryItem d = new DictionaryItem() { ParamID = nd.ParentNode.ID, Value = nd.ParamID };
                //if (Values.Contains(nd as DictionaryItem))
                if (Values.Contains(d))
                    sBuilder.Append((sBuilder.Length > 0 ? term : " ") + nd.Value.ToString());


                return sBuilder;
            };


            NextBranch_(root, fBuild);
            return sBuilder.ToString();
        }


        private void FindNext(DictionaryItem NdSource,
                                      EntityList NdVal,
                                       Func<DictionaryItem, EntityList, EntityList> fBuilder,
                                       Func<DictionaryItem, bool> CallBack)
        {
            fBuilder(NdSource, NdVal);
            // выскакиваем если дошли до вершины или до прокси ноды
            if (null == NdSource.ParentNode)
            {
                CallBack(NdSource);
                return;
            }
            if (null != NdSource.ParentNode)
            {
                if (NdSource.ParentNode.ID.IndexOf(AgencyLib_GlobalConstants.qProxyId) > -1)
                {
                    CallBack(NdSource);
                    return;
                }


                FindNext    ((NdSource.ParentNode as DictionaryItem) , NdVal, fBuilder, CallBack);
            }

        }        
        

        private void NextBranch_(DictionaryItem nd, Func<DictionaryItem, StringBuilder> fBuild)
        {
            fBuild(nd);
            nd.ChildNodes.Reset();
            List<DictionaryItem> l = nd.ChildNodes.ToList<DictionaryItem>();
            foreach (DictionaryItem i in l)
            {
                NextBranch_(i, fBuild);
            }

        }

    }


}